/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.insurance.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.insurance.domain.InsuredApply;
import me.zhengjie.modules.insurance.domain.InsuredApplyConnectRecord;
import me.zhengjie.modules.insurance.domain.InsuredApplyDoc;
import me.zhengjie.modules.insurance.handler.CityHandler;
import me.zhengjie.modules.insurance.handler.InsuranceCaseIdGenerate;
import me.zhengjie.modules.insurance.mapper.InsuredApplyConnectRecordMapper;
import me.zhengjie.modules.insurance.mapper.InsuredApplyDocMapper;
import me.zhengjie.modules.insurance.pojo.*;
import me.zhengjie.modules.insurance.service.InsuranceSchemeService;
import me.zhengjie.modules.insurance.service.InsuredUserService;
import me.zhengjie.modules.insurance.service.dto.InsuredUserDto;
import me.zhengjie.modules.system.service.DeptService;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.insurance.repository.InsuredApplyRepository;
import me.zhengjie.modules.insurance.service.InsuredApplyService;
import me.zhengjie.modules.insurance.service.dto.InsuredApplyDto;
import me.zhengjie.modules.insurance.service.dto.InsuredApplyQueryCriteria;
import me.zhengjie.modules.insurance.service.mapstruct.InsuredApplyMapper;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.sql.Timestamp;
import java.util.*;
import java.io.IOException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author HeHui
* @date 2022-01-03
**/
@Service
@RequiredArgsConstructor
@Slf4j
public class InsuredApplyServiceImpl implements InsuredApplyService {

    private final InsuredApplyRepository insuredApplyRepository;
    private final InsuredApplyMapper insuredApplyMapper;
    private final me.zhengjie.modules.insurance.mapper.InsuredApplyMapper applyMapper;
    private final InsuranceCaseIdGenerate caseIdGenerate;
    private final InsuredApplyDocMapper applyDocMapper;
    private final InsuredApplyConnectRecordMapper applyConnectRecordMapper;
    private final DeptService deptService;
    private final UserService userService;
    private final CityHandler cityHandler;
    private final InsuredUserService insuredUserService;
    private final InsuranceSchemeService insuranceSchemeService;

    @Value("${system.domain}")
    private String domain;




    @Override
    public Map<String,Object> queryAll(InsuredApplyQueryCriteria criteria, Pageable pageable){
        if (criteria.getLt() != null) {
            criteria.setLtConnectTime(new Timestamp(criteria.getLt()));
        }
        List<Long> dataScopes = SecurityUtils.getCurrentUserDataScope();
        if (CollUtil.isNotEmpty(dataScopes)) {
            if (CollUtil.isNotEmpty(criteria.getCompanyIds())) {
                List<Long> companyIds = criteria.getCompanyIds().stream().filter(dataScopes::contains).collect(Collectors.toList());
                if (CollUtil.isEmpty(companyIds)) {
                    return PageUtil.toPage(Collections.emptyList(), 0);
                }
                criteria.setCompanyIds(companyIds);
            } else {
                criteria.setCompanyIds(dataScopes);
            }
        }
        Specification<InsuredApply> specification = (root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder);

        Page<InsuredApply> page = insuredApplyRepository.findAll(specification,pageable);
        Page<InsuredApplyDto> dtos = page.map(insuredApplyMapper::toDto);
        List<InsuredApplyDto> content = dtos.getContent();
//        if (CollUtil.isNotEmpty(content)) {
//            Map<Long, Timestamp> map = page.getContent().stream().filter(v -> v.getNextConnectTime() != null).collect(Collectors.toMap(InsuredApply::getId, InsuredApply::getNextConnectTime));
//            content.forEach(v -> v.setNextConnectTime(map.get(v.getId())));
//        }
        loadInfo(content);
        return PageUtil.toPage(dtos);
    }

    /**
     * 统计
     *
     * @param criteria 标准
     * @return {@link Long}
     */
    @Override
    public Long count(InsuredApplyQueryCriteria criteria) {
        if (criteria.getLt() != null) {
            criteria.setLtConnectTime(new Timestamp(criteria.getLt()));
        }
        Specification<InsuredApply> specification = (root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder);
        return insuredApplyRepository.count(specification);
    }

    private List<InsuredApplyDto> loadInfo(List<InsuredApplyDto> content) {
        if (CollUtil.isNotEmpty(content)) {
            List<Long> companyIds = content.stream().map(InsuredApplyDto::getCompanyId).distinct().collect(Collectors.toList());
            List<Long> companySiteIds = content.stream().map(InsuredApplyDto::getCompanySiteId).distinct().collect(Collectors.toList());
            List<Long> responsibleUserIds = content.stream().map(InsuredApplyDto::getResponsibleUserId).distinct().collect(Collectors.toList());

            Map<Long, String> companyNameMap = deptService.getDeptName(companyIds);
            Map<Long, String> siteNameMap = deptService.getDeptName(companySiteIds);
            Map<Long, String> userNameMap = userService.getUserName(responsibleUserIds);

           // List<Long> applyIds = content.stream().map(InsuredApplyDto::getId).collect(Collectors.toList());


//            Map<Long, Date> applyNextConnectMap = Optional.ofNullable(applyConnectRecordMapper.findApplyLastConnectTime(applyIds))
//                .orElse(Collections.emptyList()).stream().filter(v -> v.getNextConnectTime() != null).collect(Collectors.toMap(InsuredApplyConnectRecord::getInsuredApplyId, InsuredApplyConnectRecord::getNextConnectTime, (v1, v2) -> v1));

            Map<Integer, String> caseSpeekMap = Arrays.stream(CaseSpeek.values()).collect(Collectors.toMap(CaseSpeek::getCode, CaseSpeek::getDesc));
            Map<Integer, String> caseStatusMap = Arrays.stream(CaseStatus.values()).collect(Collectors.toMap(CaseStatus::getCode, CaseStatus::getDesc));
            Date now = new Date();
            content.forEach(v -> {
                v.setCompanyName(companyNameMap.get(v.getCompanyId()));
                v.setCompanySiteName(siteNameMap.get(v.getCompanySiteId()));
                v.setResponsibleUserName(userNameMap.get(v.getResponsibleUserId()));
                v.setCaseSpeekDesc(caseSpeekMap.get(v.getCaseSpeek()));
                v.setCaseStatusDesc(caseStatusMap.get(v.getCaseStatus()));
                if (v.getNextConnectTime() != null) {
                    Date nextConnect = v.getNextConnectTime();//applyNextConnectMap.get(v.getId());
                    if (nextConnect.getTime() < now.getTime() && v.getCaseSpeek() != CaseSpeek.OVER.getCode()) {
                        long betweenDay = DateUtil.betweenDay(nextConnect, now, false);
                        if (betweenDay > 0) {
                            v.setRetentionTime(betweenDay + "天");
                        } else {
                            long hour = DateUtil.between(nextConnect, now, DateUnit.HOUR);
                            if (hour > 0) {
                                v.setRetentionTime(hour + "小时");
                            } else {
                                v.setRetentionTime(DateUtil.between(nextConnect, now, DateUnit.MINUTE) + "分钟");
                            }

                        }
                    }
                }
            });

        }
        return content;
    }

    @Override
    public List<InsuredApplyDto> queryAll(InsuredApplyQueryCriteria criteria){
        if (criteria.getLt() != null) {
            criteria.setLtConnectTime(new Timestamp(criteria.getLt()));
        }
        List<Long> dataScopes = SecurityUtils.getCurrentUserDataScope();
        if (CollUtil.isNotEmpty(dataScopes)) {
            if (CollUtil.isNotEmpty(criteria.getCompanyIds())) {
                List<Long> companyIds = criteria.getCompanyIds().stream().filter(dataScopes::contains).collect(Collectors.toList());
                if (CollUtil.isEmpty(companyIds)) {
                    return Collections.emptyList();
                }
                criteria.setCompanyIds(companyIds);
            } else {
                criteria.setCompanyIds(dataScopes);
            }
        }
        List<InsuredApply> all = insuredApplyRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder));
        List<InsuredApplyDto> content = insuredApplyMapper.toDto(all);
//        if (CollUtil.isNotEmpty(content)) {
//            Map<Long, Timestamp> map = all.stream().filter(v -> v.getNextConnectTime() != null).collect(Collectors.toMap(InsuredApply::getId, InsuredApply::getNextConnectTime));
//            content.forEach(v -> v.setNextConnectTime(map.get(v.getId())));
//        }
        return loadInfo(content);
    }

    @Override
    @Transactional
    public InsuredApplyDto findById(Long id) {
        InsuredApply insuredApply = insuredApplyRepository.findById(id).orElseGet(InsuredApply::new);
        ValidationUtil.isNull(insuredApply.getId(),"InsuredApply","id",id);
        return insuredApplyMapper.toDto(insuredApply);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public InsuredApplyDto create(InsuredApply resources) {
        return insuredApplyMapper.toDto(insuredApplyRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(InsuredApplyRequest request, long userId) {
        InsuredApply apply = applyMapper.selectByPrimaryKey(request.getId());

        if (apply == null) {
            throw new BadRequestException("案件不存在");
        }
        Integer speek = apply.getCaseSpeek();
        Date now = new Date();
        Timestamp timestamp = new Timestamp(now.getTime());
        if (existsIdApply(request.getUserIdCard(), DateUtil.beginOfDay(request.getAccidentDate()), DateUtil.endOfDay(request.getAccidentDate()), request.getId())) {
            throw new BadRequestException("该骑手今日已有案件处理中");
        }

        InsuredApply insuredApply = new InsuredApply();
        insuredApply.setId(request.getId());
        insuredApply.setLastUpdateTime(timestamp);
        insuredApply.setLastUpdateId(userId);
        insuredApply.setInsuredUserId(request.getInsuredUserId());
        insuredApply.setCompanyId(request.getCompanyId());
        insuredApply.setCompanySiteId(request.getCompanySiteId());
        insuredApply.setSiteUserName(request.getSiteUserName());
        insuredApply.setSiteUserMobile(request.getSiteUserMobile());
        insuredApply.setPolicyNo(request.getPolicyNo());
        insuredApply.setUserName(request.getUserName());
        insuredApply.setUserMobile(request.getUserMobile());
        insuredApply.setUserIdCard(request.getUserIdCard());
        insuredApply.setClaimType(request.getClaimType());
        insuredApply.setResponsibilityIds(request.getResponsibilityIds());
        insuredApply.setAdditional(request.getAdditional());


        insuredApply.setAccidentDate(new Timestamp(request.getAccidentDate().getTime()));
        insuredApply.setAccidentTypeIds(Optional.ofNullable(request.getAccidentTypeIds()).orElse(Collections.emptyList()).stream().map(String::valueOf).collect(Collectors.joining(",")));
        insuredApply.setAccidentRegionCode(Optional.ofNullable(request.getAccidentRegionCode()).orElse(Collections.emptyList()).stream().collect(Collectors.joining(",")));
        insuredApply.setAccidentAddress(request.getAccidentAddress());
        insuredApply.setAccidentDesc(request.getAccidentDesc());
        insuredApply.setResponsibleUserId(request.getResponsibleUserId());

        insuredApply.setMainInsuredCompensationAmount(null);
        insuredApply.setAdditionalMainInsuredCompensationAmount(null);
        insuredApply.setOtherAmount(null);

        if (speek.equals(CaseSpeek.WAIT_PERFECT.getCode()) && request.submitOver()) {
            insuredApply.setCaseSpeek(CaseSpeek.COLLECT_MATERIAL.getCode());
        }
        if (apply.getNextConnectTime() == null && request.getResponsibleUserId() != null && request.getResponsibleUserId() > 0) {
            insuredApply.setNextConnectTime(timestamp);
        }

        applyMapper.updateByPrimaryKeySelective(insuredApply);

        if (CollUtil.isNotEmpty(request.getFileList())) {
            applyDocMapper.deletedApplyFiles(insuredApply.getId(), 0, request.getFileList() , userId);
            List<InsuredApplyDoc> applyDocs = request.getFileList().stream().map(url -> {
                InsuredApplyDoc doc = createInsuredApplyDoc(userId, insuredApply.getId(), timestamp, url, 0);
                return doc;
            }).collect(Collectors.toList());

            applyDocMapper.deletedApplyFile(request.getId(), 0, request.getFileList(), userId);
            applyDocMapper.batchInsert(applyDocs);
        } else {
            applyDocMapper.deletedApplyFiles(insuredApply.getId(), 0, null , userId);
        }

    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            insuredApplyRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<InsuredApplyDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<Integer,String> claimTypeMap = new HashMap();
        claimTypeMap.put(1,"骑手");
        claimTypeMap.put(2,"公司");
        claimTypeMap.put(3,"三者");

        Map<String, String> responsibilittMap = new HashMap<>();
        responsibilittMap.put("1","全责");
        responsibilittMap.put("3","次责");
        responsibilittMap.put("2","主责");
        responsibilittMap.put("4","五五责");
        responsibilittMap.put("5","无责");
        responsibilittMap.put("6","摔伤");
        Map<String, String> accidentTypeIMap = new HashMap<>();
        accidentTypeIMap.put("1","自身受伤");
        accidentTypeIMap.put("2","三者受伤");
        accidentTypeIMap.put("3","三者物损");

        for (InsuredApplyDto insuredApply : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("创建日期", insuredApply.getCreateTime());
            map.put("所属公司", insuredApply.getCompanyName());
            map.put("所属站点", insuredApply.getCompanySiteName());
            map.put("站长姓名", insuredApply.getSiteUserName());
            map.put("站长手机", insuredApply.getSiteUserMobile());
            map.put("报案号", insuredApply.getReportNo());
            map.put("骑手名称", insuredApply.getUserName());
            map.put("出险人手机号码", insuredApply.getUserMobile());
            map.put("骑手身份证", insuredApply.getUserIdCard());
            map.put("理赔对象", claimTypeMap.get(insuredApply.getClaimType()));
            map.put("责任判断", responsibilittMap.get(insuredApply.getResponsibilityIds()));
            map.put("有无附加险", Objects.equals(insuredApply.getAdditional(),1) ? "有" : "无");
            map.put("案件进度", insuredApply.getCaseSpeekDesc());
            map.put("事故发生时间", insuredApply.getAccidentDate());
            map.put("出险类型", Arrays.stream(Optional.ofNullable(insuredApply.getAccidentTypeIds()).orElse("").split(",")).map(accidentTypeIMap::get).collect(Collectors.joining(",")));
            map.put("事故地址", cityHandler.getName(insuredApply.getAccidentRegionCode()) + " " + insuredApply.getAccidentAddress());
            map.put("事故说明", insuredApply.getAccidentDesc());
            map.put("理赔员", insuredApply.getResponsibleUserName());
            map.put("案件状态", insuredApply.getCaseStatusDesc());
            map.put("主险赔付金额", insuredApply.getMainInsuredCompensationAmount());
            map.put("附加险赔付金额", insuredApply.getAdditionalMainInsuredCompensationAmount());
            map.put("其他金额", insuredApply.getOtherAmount());
            map.put("结案时间", insuredApply.getOverTime() == null ? "未结案" : insuredApply.getOverTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }


    /**
     * 存在用户申请
     *
     * @param insuredUserId 被保险人的用户id
     * @param start         开始
     * @param end           结束
     * @return boolean
     */
    @Override
    public boolean existsUserApply(long insuredUserId, Date start, Date end) {
        Integer existsUserApply = applyMapper.existsUserApply(insuredUserId, start, end);
        return existsUserApply != null && existsUserApply > 0;
    }

    /**
     * 存在身份证申请
     *
     * @param userIdCard 用户id卡
     * @param start      开始
     * @param end        结束
     * @param notId      没有身份证
     * @return boolean
     */
    @Override
    public boolean existsIdApply(String userIdCard, Date start, Date end, Long notId) {
        Integer existsIdApply = applyMapper.existsIdApply(userIdCard, start, end, notId);
        return existsIdApply != null && existsIdApply > 0;
    }

    /**
     * 新增案件生气
     *
     * @param request       请求
     * @param currentUserId 当前用户id
     * @return long
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public long apply(InsuredApplyRequest request, long currentUserId) {
        if (!IdcardUtil.isValidCard(request.getUserIdCard())) {
            throw new BadRequestException("身份证号码非法");
        }
        Date now = new Date();
        Timestamp timestamp = new Timestamp(now.getTime());
        if (existsIdApply(request.getUserIdCard(), DateUtil.beginOfDay(request.getAccidentDate()), DateUtil.endOfDay(request.getAccidentDate()), null)) {
            throw new BadRequestException("该骑手今日已有案件处理中");
        }
        String reportNo = caseIdGenerate.generate("");

        InsuredApply insuredApply = new InsuredApply();
        insuredApply.setCreateUserId(currentUserId);
        insuredApply.setIsDeleted(0);
        insuredApply.setCreateTime(timestamp);
        insuredApply.setLastUpdateTime(timestamp);
        insuredApply.setLastUpdateId(currentUserId);
        insuredApply.setInsuredUserId(request.getInsuredUserId());
        insuredApply.setCompanyId(request.getCompanyId());
        insuredApply.setCompanySiteId(request.getCompanySiteId());
        insuredApply.setSiteUserName(request.getSiteUserName());
        insuredApply.setSiteUserMobile(request.getSiteUserMobile());
        insuredApply.setReportNo(reportNo);
        insuredApply.setPolicyNo(request.getPolicyNo());
        insuredApply.setUserName(request.getUserName());
        insuredApply.setUserMobile(request.getUserMobile());
        insuredApply.setUserIdCard(request.getUserIdCard());
        insuredApply.setClaimType(request.getClaimType());
        insuredApply.setResponsibilityIds(request.getResponsibilityIds());
        insuredApply.setAdditional(request.getAdditional());


        insuredApply.setAccidentDate(new Timestamp(request.getAccidentDate().getTime()));
        insuredApply.setAccidentTypeIds(Optional.ofNullable(request.getAccidentTypeIds()).orElse(Collections.emptyList()).stream().map(String::valueOf).collect(Collectors.joining(",")));
        insuredApply.setAccidentRegionCode(Optional.ofNullable(request.getAccidentRegionCode()).orElse(Collections.emptyList()).stream().collect(Collectors.joining(",")));
        insuredApply.setAccidentAddress(request.getAccidentAddress());
        insuredApply.setAccidentDesc(request.getAccidentDesc());
        insuredApply.setResponsibleUserId(request.getResponsibleUserId());

        insuredApply.setMainInsuredCompensationAmount(null);
        insuredApply.setAdditionalMainInsuredCompensationAmount(null);
        insuredApply.setOtherAmount(null);

        insuredApply.setCaseSpeek(request.submitOver() ? CaseSpeek.COLLECT_MATERIAL.getCode() : CaseSpeek.WAIT_PERFECT.getCode());
        insuredApply.setCaseStatus(CaseStatus.NOT_HANDLER.getCode());
        if (request.getResponsibleUserId() != null && request.getResponsibleUserId() > 0) {
            insuredApply.setNextConnectTime(timestamp);
        }

        applyMapper.insertSelective(insuredApply);

        if (CollUtil.isNotEmpty(request.getFileList())) {
            List<InsuredApplyDoc> applyDocs = request.getFileList().stream().filter(StringUtils::isNoneBlank).map(url -> {
                InsuredApplyDoc doc = createInsuredApplyDoc(currentUserId, insuredApply.getId(), timestamp, url, 0);
                return doc;
            }).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(applyDocs)) {
                applyDocMapper.batchInsert(applyDocs);
            }
        }

        return insuredApply.getId();
    }


    /**
     * 得到案件处理细节
     *
     * @param id id
     * @return {@link InsuredApplyHandlerDetailsResponse}
     */
    @Override
    public InsuredApplyHandlerDetailsResponse getHandlerDetails(long id) {
        InsuredApplyHandlerDetailsResponse details = applyMapper.getHandlerDetails(id);
        if (details == null) {
            return null;
        }
        Map<Long, String> deptNameMap = deptService.getDeptName(Arrays.asList(details.getCompanyId(), details.getCompanySiteId()));
        details.setCompanyName(deptNameMap.get(details.getCompanyId()));
        details.setCompanySiteName(deptNameMap.get(details.getCompanySiteId()));
        List<Long> queryUserIds = new ArrayList<>();
        if (details.getResponsibleUserId() > 0) {
            queryUserIds.add(details.getResponsibleUserId());
        }
        Map<Integer, List<String>> docMap = Optional.ofNullable(applyDocMapper.findApplyDocs(id))
            .orElse(Collections.emptyList())
            .stream().collect(Collectors.groupingBy(InsuredApplyDoc::getDocType, Collectors.mapping(v -> domain  + "/file/图片/" + v.getAccessUrl(), Collectors.toList())));
        if (docMap != null) {
            details.setMainDoc(docMap.get(0));
            details.setAdditionalDoc(docMap.get(1));
        }
        Consumer<Map<Long,String>> userConsumer = r -> {};
        List<InsuredApplyConnectRecordResponse> applyConnectRecord = applyConnectRecordMapper.findApplyConnectRecord(id);
        if (CollUtil.isNotEmpty(applyConnectRecord)) {
            List<Long> userIds = applyConnectRecord.stream().map(InsuredApplyConnectRecordResponse::getCreateUserId).distinct().collect(Collectors.toList());
            queryUserIds.addAll(userIds);
            userConsumer = userMap -> applyConnectRecord.forEach(v -> v.setCreateUserName(userMap.get(v.getCreateUserId())));
        }
        Map<Long, String> userNameMap = userService.getUserName(queryUserIds);
        userConsumer.accept(userNameMap);
        details.setResponsibleUserName(userNameMap.get(details.getResponsibleUserId()));
        details.setConnectRecords(applyConnectRecord);

        List<Long> schemeIds = new ArrayList<>(2);
        if (details.getMainScheme() != null && details.getMainScheme() > 0) {
            schemeIds.add(details.getMainScheme());
        }
        if (details.getAdditionalScheme() != null && details.getAdditionalScheme() > 0) {
            schemeIds.add(details.getAdditionalScheme());
        }
        Map<Long, String> schemeNameMap = insuranceSchemeService.getNames(schemeIds);
        details.setMainSchemeName(schemeNameMap.get(details.getMainScheme()));
        details.setAdditionalSchemeName(schemeNameMap.get(details.getAdditionalScheme()));
        return details;
    }


    /**
     * 处理
     *
     * @param request       请求
     * @param currentUserId 当前用户id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handler(InsuredApplyHandlerRequest request, long currentUserId) {
        InsuredApply insuredApply = applyMapper.selectByPrimaryKey(request.getId());
        if (insuredApply == null) {
            throw new BadRequestException("案件不存在");
        }
        Timestamp now = new Timestamp(System.currentTimeMillis());
        Integer orgCaseStatus = insuredApply.getCaseStatus();
        // 校验状态
        if (Objects.equals(orgCaseStatus, CaseStatus.CLOSE_CASE.getCode())) {
            throw new BadRequestException("案件已结不可处理!");
        }
        CaseStatus caseStatus = CaseStatus.codeOf(request.getCaseStatus());
        if (caseStatus.equals(CaseStatus.CLOSE_CASE)) {
            if (request.getMainInsuredCompensationAmount() == null) {
                throw new BadRequestException("请填入主险赔付金额");
            }
            if (Objects.equals(insuredApply.getAdditional(), 1) && request.getAdditionalMainInsuredCompensationAmount() == null) {
                throw new BadRequestException("请填入附加险赔付金额");
            }
            insuredApply.setOverTime(now);
        }

        insuredApply.setCaseStatus(request.getCaseStatus());
        insuredApply.setLastUpdateId(currentUserId);
        insuredApply.setLastUpdateTime(now);
        insuredApply.setClaimType(request.getClaimType());
        insuredApply.setAdditionalMainInsuredCompensationAmount(request.getAdditionalMainInsuredCompensationAmount());
        insuredApply.setOtherAmount(request.getOtherAmount());
        insuredApply.setMainInsuredCompensationAmount(request.getMainInsuredCompensationAmount());
        insuredApply.setMainScheme(request.getMainScheme() == null ? 0 : request.getMainScheme());
        insuredApply.setAdditionalScheme(request.getAdditionalScheme() == null ? 0 : request.getAdditionalScheme());
        if (caseStatus.getSpeek() != null) {
            insuredApply.setCaseSpeek(caseStatus.getSpeek().getCode());
        }
        if (request.getNextConnectTime() != null) {
            insuredApply.setNextConnectTime(new Timestamp(request.getNextConnectTime().getTime()));
        }

        applyMapper.updateByPrimaryKeySelective(insuredApply);

        List<InsuredApplyDoc> applyDocs = new ArrayList<>();
        if (CollUtil.isNotEmpty(request.getMainDoc())) {
            request.getMainDoc().forEach(url -> {
                applyDocs.add(createInsuredApplyDoc(currentUserId, insuredApply.getId(), now, url, 0));
            });
        }
        if (CollUtil.isNotEmpty(request.getAdditionalDoc())) {
            request.getAdditionalDoc().forEach(url -> {
                applyDocs.add(createInsuredApplyDoc(currentUserId, insuredApply.getId(), now, url, 1));
            });
        }
        if (CollUtil.isNotEmpty(applyDocs)) {
            applyDocMapper.batchInsert(applyDocs);
        }

        InsuredApplyConnectRecord record = new InsuredApplyConnectRecord();
        record.setCreateUserId(currentUserId);
        record.setIsDeleted(false);
        record.setCreateTime(now);
        record.setLastUpdateTime(now);
        record.setLastUpdateId(currentUserId);
        record.setInsuredApplyId(insuredApply.getId());
        record.setCurrentStatus(orgCaseStatus);
        record.setSubmitStatus(request.getCaseStatus());
        record.setConnectContent(request.getConnectContent());
        record.setConnectType(request.getConnectType());
        record.setNextConnectTime(request.getNextConnectTime());
        record.setCaseRemarks(request.getCaseRemarks());
        record.setAdditionalMainInsuredCompensationAmount(request.getAdditionalMainInsuredCompensationAmount());
        record.setOtherAmount(request.getOtherAmount());
        record.setMainInsuredCompensationAmount(request.getMainInsuredCompensationAmount());

        record.setUploadDocIds(applyDocs.stream().filter(v -> v.getId() != null).map(InsuredApplyDoc::getId).map(String::valueOf).collect(Collectors.joining(",")));


        applyConnectRecordMapper.insertSelective(record);

    }


    /**
     * 加载更新数据
     *
     * @param id id
     * @return {@link InsuredApplyRequest}
     */
    @Override
    public InsuredApplyRequest loadUpdateData(long id) {
        InsuredApply insuredApply = applyMapper.selectByPrimaryKey(id);
        if (insuredApply == null) {
            throw new BadRequestException("数据不存在");
        }
        InsuredApplyRequest request = loadUpdateData(id, insuredApply);
        return request;
    }


    private InsuredApplyRequest loadUpdateData(long id, InsuredApply insuredApply) {
        InsuredApplyRequest request = new InsuredApplyRequest();
        request.setId(insuredApply.getId());
        request.setInsuredUserId(insuredApply.getInsuredUserId());
        request.setCompanyId(insuredApply.getCompanyId());
        request.setCompanySiteId(insuredApply.getCompanySiteId());
        request.setSiteUserName(insuredApply.getSiteUserName());
        request.setSiteUserMobile(insuredApply.getSiteUserMobile());
        request.setReportNo(insuredApply.getReportNo());
        request.setPolicyNo(insuredApply.getPolicyNo());
        request.setUserName(insuredApply.getUserName());
        request.setUserMobile(insuredApply.getUserMobile());
        request.setUserIdCard(insuredApply.getUserIdCard());
        request.setClaimType(insuredApply.getClaimType());
        request.setResponsibilityIds(insuredApply.getResponsibilityIds());
        request.setAdditional(insuredApply.getAdditional());
        request.setAccidentDate(insuredApply.getAccidentDate());
        request.setAccidentTypeIds(insuredApply.getAccidentTypeIds() == null ? null : StrUtil.split(insuredApply.getAccidentTypeIds(), ',').stream().map(Integer::valueOf).collect(Collectors.toList()));
        request.setAccidentRegionCode(insuredApply.getAccidentRegionCode() == null ? null : StrUtil.split(insuredApply.getAccidentRegionCode(), ',').stream().collect(Collectors.toList()));
        request.setAccidentAddress(insuredApply.getAccidentAddress());
        request.setAccidentDesc(insuredApply.getAccidentDesc());
        request.setResponsibleUserId(insuredApply.getResponsibleUserId() == null || insuredApply.getResponsibleUserId() < 1 ? null : insuredApply.getResponsibleUserId());

        List<InsuredApplyDoc> applyDocs = applyDocMapper.findApplyDocs(id);
        if (CollUtil.isNotEmpty(applyDocs)) {
            request.setFileList(applyDocs.stream().filter(v -> v.getDocType().equals(0)).map(InsuredApplyDoc::getAccessUrl).collect(Collectors.toList()));
        }
        return request;
    }


    /**
     * 更新理赔员
     *
     * @param ids                id
     * @param responsibleUserId 负责用户id
     * @param currentUserId     当前用户id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUser(List<Long> ids, long responsibleUserId, long currentUserId) {
        applyMapper.updateUser(ids, responsibleUserId, currentUserId);
        List<Long> existsApplyIds = applyDocMapper.existsApplyDoc(ids);
        if (CollUtil.isNotEmpty(existsApplyIds)) {
            applyMapper.submitOver(existsApplyIds);
        }
    }

    /**
     * 统计当前用户 指定时间内人沟通案件数
     *
     * @param start         开始
     * @param end           结束
     * @param currentUserId 当前用户id
     * @return {@link Integer}
     */
    @Override
    public Integer countNextTime(Date start, Date end, long currentUserId) {
        Integer countNextTime = applyConnectRecordMapper.countNextTime(start, end, currentUserId);
        if (countNextTime == null) {
            return 0;
        }
        return countNextTime;
    }

    /**
     * 手机号码匹配匹配
     *
     * @param mobile 移动
     * @param start  开始
     * @param end    结束
     * @return {@link InsuredApplyRequest}
     */
    @Override
    public InsuredApplyRequest mobileMatching(String mobile, Date start, Date end) {
        InsuredApply apply = applyMapper.mobileMatching(mobile, start, end);
        if (apply == null) {
            return null;
        }

        return loadUpdateData(apply.getId(), apply);
    }

    /**
     * 补充文件
     *
     * @param docs 文档
     * @param id   id
     */
    @Override
    public void replenishDoc(List<String> docs, long id) {
        Timestamp now = new Timestamp(System.currentTimeMillis());
        List<InsuredApplyDoc> docList = docs.stream().map(u -> createInsuredApplyDoc(0L, id, now, u, 0)).collect(Collectors.toList());
        applyDocMapper.batchInsert(docList);
    }

    /**
     * 查看进度
     *
     * @param id id
     * @return {@link InsuredCaseSpeedResponse}
     */
    @Override
    public InsuredCaseSpeedResponse getSpeed(long id) {
        InsuredApply insuredApply = applyMapper.selectByPrimaryKey(id);
        if (insuredApply == null) {
            return null;
        }
        InsuredCaseSpeedResponse response = new InsuredCaseSpeedResponse();
        response.setId(id);
        response.setSpeed(CaseSpeek.codeOf(insuredApply.getCaseSpeek()).getDesc());

        InsuredApplyConnectRecord applyLast = applyConnectRecordMapper.getApplyLast(id);
        response.setContent("待沟通");
        response.setAmount("待定损");
        if (applyLast != null) {
            response.setContent(applyLast.getConnectContent());
            StringBuilder sb = new StringBuilder("主险:");
            sb.append(applyLast.getMainInsuredCompensationAmount());

            if (applyLast.getAdditionalMainInsuredCompensationAmount() != null) {
                sb.append("附加险:").append(applyLast.getAdditionalMainInsuredCompensationAmount());
            }
            if (applyLast.getOtherAmount() != null) {
                sb.append("其他:").append(applyLast.getOtherAmount());
            }
            response.setAmount(sb.toString());
        }

        return response;
    }


    /**
     * 用户申请
     *
     * @param request 请求
     * @return {@link Long}
     */
    @Override
    public Long userApply(InsuredUserApplyRequest request) {
        if (!IdcardUtil.isValidCard(request.getUserIdCard())) {
            throw new BadRequestException("身份证号码非法");
        }
        Date now = new Date();
        Timestamp timestamp = new Timestamp(now.getTime());
        if (existsIdApply(request.getUserIdCard(), DateUtil.beginOfDay(request.getAccidentDate()), DateUtil.endOfDay(request.getAccidentDate()), null)) {
            throw new BadRequestException("您该日已有案件处理中");
        }
        String reportNo = caseIdGenerate.generate("");
        MatchingSiteRequest matchingSiteRequest = new MatchingSiteRequest();
        matchingSiteRequest.setUserName(request.getUserName());
        matchingSiteRequest.setUserIdCard(request.getUserIdCard());
        matchingSiteRequest.setAccidentDate(request.getAccidentDate());
        InsuredUserDto matching = insuredUserService.matching(matchingSiteRequest);


        InsuredApply insuredApply = new InsuredApply();
        insuredApply.setCreateUserId(0L);
        insuredApply.setIsDeleted(0);
        insuredApply.setCreateTime(timestamp);
        insuredApply.setLastUpdateTime(timestamp);
        insuredApply.setLastUpdateId(0L);
        insuredApply.setInsuredUserId(matching == null ? 0L : matching.getId());
        insuredApply.setCompanyId(matching == null ? 0L : matching.getOwnerCompanyId());
        insuredApply.setCompanySiteId(0L);
        insuredApply.setSiteUserName("");
        insuredApply.setSiteUserMobile("");
        insuredApply.setReportNo(reportNo);
        insuredApply.setPolicyNo("");
        insuredApply.setUserName(request.getUserName());
        insuredApply.setUserMobile(request.getUserMobile());
        insuredApply.setUserIdCard(request.getUserIdCard());
        insuredApply.setClaimType(request.getClaimType());
        insuredApply.setResponsibilityIds(request.getResponsibilityIds());
        insuredApply.setAdditional(matching == null ? 0 : 1);


        insuredApply.setAccidentDate(new Timestamp(request.getAccidentDate().getTime()));
        insuredApply.setAccidentTypeIds(Optional.ofNullable(request.getAccidentTypeIds()).orElse(Collections.emptyList()).stream().map(String::valueOf).collect(Collectors.joining(",")));
        insuredApply.setAccidentRegionCode(Optional.ofNullable(request.getAccidentRegionCode()).orElse(Collections.emptyList()).stream().collect(Collectors.joining(",")));
        insuredApply.setAccidentAddress(request.getAccidentAddress());
        insuredApply.setAccidentDesc(request.getAccidentDesc());
        insuredApply.setResponsibleUserId(0L);

        insuredApply.setMainInsuredCompensationAmount(null);
        insuredApply.setAdditionalMainInsuredCompensationAmount(null);
        insuredApply.setOtherAmount(null);

        insuredApply.setCaseSpeek(CaseSpeek.WAIT_PERFECT.getCode());
        insuredApply.setCaseStatus(CaseStatus.NOT_HANDLER.getCode());

        applyMapper.insertSelective(insuredApply);

        log.info("[案件管理] user apply case id:{}", insuredApply.getId());
        if (CollUtil.isNotEmpty(request.getFileList())) {
            List<InsuredApplyDoc> applyDocs = request.getFileList().stream().map(url -> {
                InsuredApplyDoc doc = createInsuredApplyDoc(0L, insuredApply.getId(), timestamp, url, 0);
                return doc;
            }).collect(Collectors.toList());

            applyDocMapper.batchInsert(applyDocs);

        }

        return insuredApply.getId();
    }


    /**
     * 用户编辑
     *
     * @param request 请求
     */
    @Override
    public void userEdit(InsuredUserUpdateRequest request) {
        Integer speek = applyMapper.getSpeek(request.getId());
        if (speek == null) {
            throw new BadRequestException("案件不存在");
        }
        if (Objects.equals(speek, CaseSpeek.OVER.getCode())) {
            throw new BadRequestException("案件已结不可编辑");
        }

        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        InsuredApply apply = new InsuredApply();
        apply.setId(request.getId());
        apply.setLastUpdateTime(timestamp);
        apply.setAccidentTypeIds(Optional.ofNullable(request.getAccidentTypeIds()).orElse(Collections.emptyList()).stream().map(String::valueOf).collect(Collectors.joining(",")));
        apply.setAccidentRegionCode(Optional.ofNullable(request.getAccidentRegionCode()).orElse(Collections.emptyList()).stream().collect(Collectors.joining(",")));
        apply.setAccidentAddress(request.getAccidentAddress());
        apply.setAccidentDesc(request.getAccidentDesc());

        applyMapper.updateByPrimaryKeySelective(apply);
        log.info("[案件管理] user edit case id:{}", apply.getId());

        if (CollUtil.isNotEmpty(request.getNewFileList())) {
            List<InsuredApplyDoc> applyDocs = request.getNewFileList().stream().map(url -> {
                InsuredApplyDoc doc = createInsuredApplyDoc(0L, apply.getId(), timestamp, url, 0);
                return doc;
            }).collect(Collectors.toList());

            applyDocMapper.batchInsert(applyDocs);
        }

    }

    private InsuredApplyDoc createInsuredApplyDoc(long currentUserId, long applyId, Timestamp now, String url, int type) {
        InsuredApplyDoc doc = new InsuredApplyDoc();
        doc.setCreateUserId(currentUserId);
        doc.setIsDeleted(false);
        doc.setCreateTime(now);
        doc.setLastUpdateTime(now);
        doc.setLastUpdateId(currentUserId);
        doc.setInsuredApplyId(applyId);
        doc.setFileName("");
        doc.setAccessUrl(url);
        doc.setDocType(type);
        return doc;
    }
}